package mth.masterimp;

import rs.fon.whibo.GC.component.DistanceMeasure.DistanceMeasure;

public class Neighborhood {
	/*
	 * Diese Klasse dient der Repräsentation der Nachbarschaften. Neben einem static Zähler
	 * für die Anzahl der Nachbarschaften existieren auch spezielle Methoden zur Berechnung der
	 * Nachbarschaftsrepräsentanten und zur Kombination von Nachbarschaften.
	 */
	
	private static int NUMBER_OF_NEIGHBORHOODS;
	private int number;
	private int[] member;
	private ClusterRepresentatives crep;
	private DataRepresentator dr;
	
	
	Neighborhood(int num) {
		number=num;
		NUMBER_OF_NEIGHBORHOODS++;
		crep=null; //the method calculateClusterRepresentative() has to be called explicitly
		dr=new DataRepresentator();
	}
	
	public void addMember(int m) {
		if (member==null || member.length==0) {
			member = new int[1];
			member[0]=m;
		} else {
			if (!containsMember(m)) {
				int[] helper = new int[member.length];
				helper=member;
				member=new int[member.length+1];
				for (int a=0; a<helper.length; a++)
					member[a]=helper[a];
				
				member[helper.length] = m;
			} else {
				//noting to do here?
			}
		}
	}
	
	public void calculateClusterRepresentative() {
		if (crep==null) {
			int nbhood=number;
			int vmri=member[0];
			double[] mean = new double[dr.getValueMatrix().getNumberOfColumns()-dr.getValueMatrix().getNumberOfSpecialColumns()];
			for (int a=0; a<mean.length; a++) {
				int b=0;
				while (b<member.length) {
					double[] tmp = Tools.extractDoubleArrayFromDataRow(dr.getValueMatrix().getRow(member[b]));
					mean[a]+=tmp[a];
					b++;
				}
				mean[a]=mean[a]/b;
			}
			
			try {
				double[] distanceToCenter = new double[member.length];
				DistanceMeasure d = dr.generateDistanceMeasure(dr.getDistanceMeasure(), null);
				for (int a=0; a<member.length; a++) {
					distanceToCenter[a]=d.calculateDistance(mean, Tools.extractDoubleArrayFromDataRow(dr.getValueMatrix().getRow(member[a])));
				}
				double centerDistance=distanceToCenter[0];
				for (int a=0; a<distanceToCenter.length-1; a++) {
					if (centerDistance<distanceToCenter[a+1]) {
						vmri=member[a];
						centerDistance=distanceToCenter[a+1];
					}
				}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			crep=new ClusterRepresentatives(nbhood, vmri);
		}
	}
	
	public Neighborhood combineNeighborhoods(Neighborhood n1, Neighborhood n2) {
		for (int a=0; a<n2.member.length; a++) {
			if (!n1.containsMember(n2.getMember()[a])) {
				n1.addMember(n2.getMember()[a]);
			}
		}
		n2=null;
		NUMBER_OF_NEIGHBORHOODS--;
		return n1;
	}
	
	public boolean containsMember(int m) {
		if (member==null || member.length==0) 
			return false;
		for (int a=0; a<member.length; a++) {
			if (member[a]==m)
				return true;
		}
		return false;
	}
	
	public ClusterRepresentatives getCRep() {
		return crep;
	}
	
	public int getCRepRowID() {
		return crep.getValueMatrixRowID();
	}
	
	public int getNumber() {
		return number;
	}
	
	public int[] getMember() {
		return member;
	}
	
	public static int getNumberOfNeighborhoods() {
		return NUMBER_OF_NEIGHBORHOODS;
	}
	
	public void nullCRep() {
		crep=null;
	}
	
	public void removeMember(int m) {
		boolean removed=false;
		for (int a=0; a<member.length-1; a++) {
			if (removed) {
				member[a]=member[a+1];
			} else {
				if (member[a]==m) {
					member[a]=member[a+1];
					removed=true;
				}
			}
		}
		int[] helper = new int[member.length-1];
		for (int a=0; a<helper.length; a++) {
			helper[a]=member[a];
		}
		member = new int[helper.length];
		member = helper;
//		System.out.println("removed: "+m+" length now: "+member.length);
	}
	
	public void updateNumber(int n) { //USE WITH CARE!!!
		number=n;
	}
}
